<template>
  <div ref="threeDiv">
    <Renderer
      class="threeDiv"
      ref="renderer"
      resize="window"
      :pointer="true"
      :orbitCtrl="true"
      :alpha="true"
    >
      <Camera ref="camera" :position="c_position" />
      <Scene ref="scene" />
    </Renderer>
  </div>
</template>

<script setup lang="ts">
  import { Renderer, Scene, Camera } from 'troisjs';
  import * as THREE from 'three';
  import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
  import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
  import * as dat from 'dat.gui';
  import { onMounted, ref } from 'vue';
  import { notification } from 'ant-design-vue';
  import { Icon } from '/@/components/Icon';

  const threeDiv: any = ref(); // 界面组件
  const renderer: any = ref(null); // 渲染器
  const scene: any = ref();
  const camera: any = ref(); // 相机
  let orbitCtrl: any; // 控制器
  let refreshLedPositionTimer: any;

  let c_position = { x: 5.444932134769378, y: 0.8745255704200192, z: -6.424215661879478 }; // 相机位置参数
  let ambient: any, pointLight: any, hemisphereLight: any;

  onMounted(() => {
    init();
    // 渲染
    render();
  });

  // 页面初始化
  function init() {
    // addDiban(); // 创建底板
    addLight();
    addGltfs();

    threeDiv.value.addEventListener('mousedown', onMouseClick, false); // 点击事件
  }

  function render() {
    // 循环渲染
    renderer.value.onBeforeRender(() => {});
  }

  // 创建底板
  function addDiban() {
    // 创建底板并添加到场景
    const planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1);
    const planeMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff });
    const plane = new THREE.Mesh(planeGeometry, planeMaterial);
    plane.rotation.x = -0.5 * Math.PI;
    plane.position.x = 0;
    plane.position.y = -5;
    plane.position.z = 0;
    scene.value.add(plane);
  }

  // 灯光
  function addLight() {
    //点光源1
    pointLight = new THREE.PointLight(0xffffff);
    pointLight.position.set(6.69, 12.21, -7.64); //点光源位置
    // pointLight.intensity = 0.3;
    scene.value.add(pointLight); //点光源添加到场景中

    //环境光
    ambient = new THREE.AmbientLight(0x1c1e1c);
    scene.value.add(ambient);

    hemisphereLight = new THREE.HemisphereLight(0x12141e);
    hemisphereLight.position.set(0, 1, 0); //点光源位置
    scene.value.add(hemisphereLight);
  }

  // 添加gltf模型文件
  function addGltfs() {
    const loader = new GLTFLoader();
    const dracoLoader = new DRACOLoader();
    dracoLoader.setDecoderPath('/static/draco3dgltf/');
    loader.setDRACOLoader(dracoLoader);

    loader.load(
      '/static/models/test.gltf',
      (gltf: any) => {
        onReady(gltf);
      },
      onProgress,
      onError,
    );
  }

  // 模型加载完成
  function onReady(res) {
    console.log('模型加载完成', res);
    scene.value.add(res.scene);
    const box3 = new THREE.Box3();
    box3.expandByObject(res.scene);
    const center = new THREE.Vector3();
    box3.getCenter(center);
    // 重新设置模型的位置，使之居中。
    res.scene.position.x = res.scene.position.x - center.x;
    res.scene.position.y = res.scene.position.y - center.y;
    res.scene.position.z = res.scene.position.z - center.z;

    orbitCtrl = renderer.value.three.cameraCtrl;
    orbitCtrl.addEventListener('end', () => {
      // 相机视角更改事件
      refreshLedPositionTimer = setTimeout(() => {
        // console.log('更改相机事件', camera.value); // 相机值没有更改,需要通过事件重新获取相机信息
      }, 200);
    });

    orbitCtrl.addEventListener('start', () => {
      clearTimeout(refreshLedPositionTimer);
    });

    addGui(); // 调试工具
    tishi(); // 操作提示
  }

  // 模型加载进度条
  function onProgress(res) {
    let jindu = Math.round((res.loaded / res.total) * 100);
    console.log('模型加载进度条', jindu);
  }

  // 模型加载错误
  function onError(res) {
    console.log('模型加载错误', res);
  }

  // 点击事件
  function onMouseClick(event: any) {
    event.preventDefault();
    let positionN = renderer.value.three.pointer.positionN;
    let raycaster = new THREE.Raycaster();
    raycaster.setFromCamera(positionN, camera.value.camera);
    let intersects: any = raycaster.intersectObjects(scene.value.scene.children, true);
    console.log('选中的模型', intersects);
    if (intersects[0]) {
      // intersects[0].object.material.color.set(0x0000ff);
    }
  }

  // 配置光
  function addGui() {
    const data = {
      color: ambient.color.getHex(),
      groundColor: hemisphereLight.groundColor.getHex(),
      mapsEnabled: true,
    };
    const gui: any = new dat.GUI();
    const lightFolder = gui.addFolder('环境光');
    lightFolder.addColor(data, 'color').onChange(() => {
      ambient.color.setHex(Number(data.color.toString().replace('#', '0x')));
    });
    lightFolder.add(ambient, 'intensity', 0, 1, 0.01);

    const pointLightFolder = gui.addFolder('点光源');
    pointLightFolder.add(pointLight, 'distance', 0, 100, 0.01);
    pointLightFolder.add(pointLight, 'decay', 0, 4, 0.1);
    pointLightFolder.add(pointLight.position, 'x', -50, 50, 0.01);
    pointLightFolder.add(pointLight.position, 'y', -50, 50, 0.01);
    pointLightFolder.add(pointLight.position, 'z', -50, 50, 0.01);

    const hemisphereLightFolder = gui.addFolder('半球灯光');
    hemisphereLightFolder.addColor(data, 'groundColor').onChange(() => {
      hemisphereLight.groundColor.setHex(Number(data.groundColor.toString().replace('#', '0x')));
    });
    hemisphereLightFolder.add(hemisphereLight.position, 'x', -1000, 1000, 0.01);
    hemisphereLightFolder.add(hemisphereLight.position, 'y', -1000, 1000, 0.01);
    hemisphereLightFolder.add(hemisphereLight.position, 'z', -1000, 1000, 0.01);
  }

  // 操作提示
  function tishi() {
    notification.open({
      message: '模型操作方法',
      description:
        '1. 按下鼠标左键，移动鼠标 ==》 旋转模型' +
        `\n` +
        '2. 滚动鼠标中键 ==》 缩放模型' +
        `\n` +
        '3. 按下鼠标右键，移动鼠标 ==》 移动模型',
      duration: 0,
      placement: 'bottomLeft',
      style: {
        whiteSpace: 'pre-wrap',
      },
    });
  }
</script>

<style lang="less">
  .threeDiv {
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    background-image: linear-gradient(rgb(170, 162, 113), rgb(80, 85, 92));
  }

  .dg.a {
    margin-top: 35px;
  }
</style>
